#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>

MODULE_AUTHOR("Arkins");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Virtual Bus");

#define VBUS_NAME "vbus"
#define VBUS_DEV_NAME "vdev"

static int vbus_match(struct device *dev, struct device_driver *gendrv);
static void vclass_release(struct device *class_dev);

static struct bus_type vbus = {
    .name   = VBUS_NAME,
    .match  = vbus_match,
};

static struct class vclass = {
	.name        = "vclass",
	.dev_release = vclass_release,
};

// vbus下的设备都是vdevice的子设备
static struct device vbus_dev = {
    .init_name	= VBUS_DEV_NAME,
};

static int vbus_match(struct device *dev, struct device_driver *drv)
{
    printk("vbus_match\n");
    if (dev == NULL) {
        printk("vbus_match dev == NULL\n");
    }
    if (drv == NULL) {
        printk("vbus_match drv == NULL\n");
    }
    if (dev != NULL && drv != NULL) {
        printk("vbus_match dev != NULL && drv != NULL\n");
    }

    if (dev != NULL && dev->bus != NULL) {
        printk("vbus_match dev->init_name %s\n", dev->init_name);
        printk("vbus_match dev->bus->name %s\n", dev->bus->name);
        printk("vbus_match dev->bus->dev_name %s\n", dev->bus->dev_name);
    }
    if (drv != NULL) {
        printk("vbus_match drv->name %s\n", drv->name);
        printk("vbus_match drv->bus->name %s\n", drv->bus->name);
    }
    if (drv->bus == &vbus) {
        dev->driver = drv;
        drv->probe(dev);
        printk("vbus_match success\n");
        return 0;
    }
    printk("vbus_match fail\n");
    return 1;
}

static void vclass_release(struct device *class_dev)
{
    printk("vclass_release");
}


int vbus_register_driver(struct device_driver *drv)
{
    drv->bus = &vbus;
    return driver_register(drv);
}
EXPORT_SYMBOL(vbus_register_driver);

void vbus_unregister_driver(struct device_driver *drv)
{
    driver_unregister(drv);
    // drv->bus = NULL;
}
EXPORT_SYMBOL(vbus_unregister_driver);

int vbus_register_device(struct device *dev)
{
    dev->bus = &vbus;
    dev->parent = &vbus_dev;
    return device_register(dev);
}
EXPORT_SYMBOL(vbus_register_device);

void vbus_unregister_device(struct device *dev)
{
    device_unregister(dev);
    // dev->bus = NULL;
    // dev->parent = NULL;
}
EXPORT_SYMBOL(vbus_unregister_device);

static void vbus_unregister(int ret, int level)
{
    if (ret != 0 && level > 2) {
        class_unregister(&vclass);
        printk("vbus_init: class_register error\n");
    }
    if (ret != 0 && level > 1) {
        device_unregister(&vbus_dev);
        printk("vbus_init: device_register error\n");
    }
    if (ret != 0 && level > 0) {
        bus_unregister(&vbus);
        printk("vbus_init: bus_register error\n");
    }
    return ret;
}

#define check_ret(ret, level)           \
    vbus_unregister((ret), (level));    \
    if (ret != 0) return 1;             \

static int __init vbus_init(void)
{
    int ret;
    printk("vbus_init\n");
    ret = bus_register(&vbus);
    check_ret(ret, 0);

    ret = device_register(&vbus_dev);
    check_ret(ret, 1);

    ret = class_register(&vclass);
    check_ret(ret, 2);
    return 0;
}

static void __exit vbus_exit(void)
{
    printk("vbus_exit\n");
    vbus_unregister(1, 3);
}

module_init(vbus_init)
module_exit(vbus_exit)
